package io.gitee.tziye.core.instance;

import com.zaxxer.hikari.HikariDataSource;
import io.gitee.tziye.RenaiClient;
import io.gitee.tziye.core.bloom.DefaultBloomOperator;
import io.gitee.tziye.core.fs.DefaultFsOperator;
import io.gitee.tziye.core.id.DefaultIdOperator;
import io.gitee.tziye.core.kv.impl.DefaultListOperator;
import io.gitee.tziye.core.kv.impl.DefaultMapOperator;
import io.gitee.tziye.core.kv.impl.DefaultPairOperator;
import io.gitee.tziye.core.kv.impl.DefaultPriorityQOperator;
import io.gitee.tziye.core.lock.DefaultLockOperator;
import io.gitee.tziye.core.msg.DefaultMsgOperator;
import io.gitee.tziye.core.search.DefaultSearchOperator;
import io.gitee.tziye.enums.InstanceStatus;
import io.gitee.tziye.jdbc.JdbcProxy;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Getter
public class DefaultRenaiClient extends RenaiClient {

    private final HikariDataSource dataSource;
    private final JdbcProxy jdbcProxy;

    public DefaultRenaiClient(RenaiDataSource renaiDataSource) {
        this(renaiDataSource, new InstanceSpec());
    }

    public DefaultRenaiClient(RenaiDataSource renaiDataSource, InstanceSpec instanceSpec) {
        super(instanceSpec);
        dataSource = new HikariDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl(renaiDataSource.getUrl());
        dataSource.setSchema(renaiDataSource.getDatabase());
        dataSource.setUsername(renaiDataSource.getUser());
        dataSource.setPassword(renaiDataSource.getPassword());
        dataSource.setMaximumPoolSize(renaiDataSource.getMaxConnections());
        dataSource.setIdleTimeout(renaiDataSource.getMaxIdleSeconds() * 1000L);
        dataSource.setPoolName("Renai-Pool");
        jdbcProxy = new JdbcProxy(dataSource);
        init();
    }

    public void init() {
        super.pairOperator = new DefaultPairOperator(this);
        super.listOperator = new DefaultListOperator(this);
        super.priorityQOperator = new DefaultPriorityQOperator(this);
        super.mapOperator = new DefaultMapOperator(this);
        super.msgOperator = new DefaultMsgOperator(this);
        super.lockOperator = new DefaultLockOperator(this);
        super.searchOperator = new DefaultSearchOperator(this);
        super.fsOperator = new DefaultFsOperator(this);
        super.idOperator = new DefaultIdOperator(this);
        super.bloomOperator = new DefaultBloomOperator(this);
    }

    @Override
    public void register() {
        SCHEDULER.scheduleWithFixedDelay(() -> {
            if (jdbcProxy != null && enableRegister) {
                doRegister(InstanceStatus.Live);
            }
        }, 2, 5, TimeUnit.SECONDS);
    }

    @Override
    public void shutdown() {
        SCHEDULER.shutdownNow();
        if (enableRegister) {
            doRegister(InstanceStatus.Dead);
        }
    }

    public void doRegister(InstanceStatus status) {
        String sql = """
                INSERT INTO renai_instance(instance_id, g, service, ip, port, status) VALUES (?, ?, ?, ?, ?, ?)
                    ON DUPLICATE KEY UPDATE g = VALUES(g), service = VALUES(service), ip = VALUES(ip),
                        port = VALUES(port), status = VALUES(status), update_time = NOW()""";
        jdbcProxy.update(sql, instance.getInstanceId(), instance.getG(), instance.getService(),
                instance.getIp(), instance.getPort(), status.name());
        instance.setStatus(status.name());
    }

    @Override
    public RenaiInstance realStatus() {
        String sql = "SELECT * FROM renai_instance WHERE instance_id = ?";
        List<RenaiInstance> instances = jdbcProxy.query(sql,
                new BeanPropertyRowMapper<>(RenaiInstance.class), instance.getInstanceId());
        return CollectionUtils.isEmpty(instances) ? instance : instances.get(0);
    }

    @Override
    public List<RenaiInstance> instances() {
        return lookup(instance.getG(), instance.getService());
    }

    @Override
    public List<RenaiInstance> lookup(String group, String service) {
        String sql = "SELECT * FROM renai_instance_valid WHERE g = ? AND service = ?";
        return jdbcProxy.query(sql, new BeanPropertyRowMapper<>(RenaiInstance.class),
                group, service);
    }

}
